#include "ET++.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "CompVObject.h"

#include "Class.h"
#include "OrdColl.h"
#include "ET_stdio.h"

//---- CompositeVObject --------------------------------------------------------

NewAbstractMetaImpl(CompositeVObject,VObject, (TP(list)));

CompositeVObject::CompositeVObject(int id, SeqCollection *cp) : VObject(id)
{
	list= cp;
	if (list) {
		list->ForEach(VObject,SetContainer)(this);
		islist= TRUE;
	} else
		islist= FALSE;
}

CompositeVObject::CompositeVObject(int va_(id), ...) : VObject(va_(id))
{
	va_list ap;
	va_start(ap,va_(id));
	list= 0;
	islist= FALSE;
	SetItems(ap);
	va_end(ap);
}

CompositeVObject::CompositeVObject(int id, va_list ap) : VObject(id)
{
	list= 0;
	islist= FALSE;
	SetItems(ap);
}

CompositeVObject::~CompositeVObject()
{
	if (list) {
		if (islist) {
			SeqCollection *tmp= list;
			list= 0;
			islist= FALSE;
			tmp->ForEach(VObject,ClearContainer)(this);
			tmp->FreeAll();
			delete tmp;
		} else {
			((VObject*)list)->ClearContainer(this);
			SafeDelete(list);
		}
	}
}

VObject *CompositeVObject::At(int n)
{
	if (list) {
		if (islist)
			return (VObject*)list->At(n);
		if (n == 0)
			return (VObject*)list;
		fprintf(stderr, "CompositeVObject::At: %d out of range\n", n);
	}
	return 0;
}

int CompositeVObject::Size()
{
	if (list) {
		if (islist)
			return list->Size();
		return 1;
	}
	return 0;
}

void CompositeVObject::Add(VObject *vop)
{
	if (vop) {
		if (list == 0) {
			list= (OrdCollection*) vop;
			islist= FALSE;
		} else {
			if (!islist) {
				Object *tmp= list;
				list= new OrdCollection;
				list->Add(tmp);
				islist= TRUE;
			}
			list->Add(vop);
		}
		vop->SetContainer(this);
		if (IsOpen()) {
			vop->Open();
			/*
			ForceRedraw();
			Point e= GetMinSize().extent;
			Point ee= GetExtent();
			if (e.x > ee.x || e.y > ee.y)
				ExtentChanged(this);
			else {
				SetExtent(GetExtent());
				SetOrigin(GetOrigin());
			}
			*/
		}
	}
}

VObject *CompositeVObject::Remove(VObject *vop)
{
	if (list) {
		VObject *old= 0;
		if (vop && vop->IsOpen()) {
			vop->Close();
			vop->ClearContainer(this);
		}
		if (islist) {
			old= (VObject*) list->RemovePtr(vop);
		} else {
			islist= FALSE;
			if (vop == (VObject*) list) {
				list= 0;
				old= vop;
			}
		}
		if (IsOpen()) {
			ForceRedraw();
			Point e= GetMinSize().extent;
			Point ee= GetExtent();
			if (e.x > ee.x || e.y > ee.y)
				ExtentChanged(this);
			else {
				SetExtent(GetExtent());
				SetOrigin(GetOrigin());
			}
		}
		return old;
	}
	return 0;
}

VObject *CompositeVObject::SetAt(int at, VObject *vop)
{
	VObject *old= 0;

	if (vop && at < Size()) {
		if (list == 0) {
			list= new OrdCollection;
			islist= TRUE;
		} else {
			if (islist)
				;
			else {
				Object *tmp= list;
				list= new OrdCollection;
				list->Add(tmp);
				islist= TRUE;
			}
		}

		if (at >= 0) {
			old= At(at);
			if (old) {
				if (old->IsOpen())
					old->Close();
				old->ClearContainer(this);
			}
			list->PutAt(vop, at);
		} else {
			list->AddFirst(vop);
		}
		vop->SetContainer(this);
		if (IsOpen()) {
			vop->Open();
			ForceRedraw();
			Point e= GetMinSize().extent;
			Point ee= GetExtent();
			if (e.x > ee.x || e.y > ee.y)
				ExtentChanged(this);
			else {
				SetExtent(GetExtent());
				SetOrigin(GetOrigin());
			}
		}
	}
	return old;
}

Iterator *CompositeVObject::MakeIterator(bool dir, void *placement)
{
	if (list) {
		if (islist)
			return list->MakeIterator(dir, placement);
		return new(placement) Iterator1(list);
	}
	return VObject::MakeIterator(dir, placement);
}

void CompositeVObject::DoObserve(int, int part, void*, Object *op)
{
	if (op == list && part == cPartSenderDied)
		list= 0;
}

SeqCollection *CompositeVObject::GetList()
{
	if (!islist) {
		Object *tmp= list;
		list= new OrdCollection;
		list->Add(tmp);
		islist= TRUE;
	}
	return list;
}

void CompositeVObject::SetItems(va_list ap)
{
	register VObject *op;

	while (op= va_arg(ap, VObject*))
		Add(op);
}

void CompositeVObject::SetItems(VObject *vop, va_list ap)
{
	register VObject *op;
	if (vop)
		Add(vop);
	while (op= va_arg(ap, VObject*))
		Add(op);
}

void CompositeVObject::SetOrigin(Point origin)
{
	VObject::SetOrigin(origin);
	VObjectIter next(this);
	register VObject *vop;

	while (vop= next())
		vop->SetOrigin(origin);
}

void CompositeVObject::SetExtent(Point extent)
{
	VObject::SetExtent(extent);
	VObjectIter next(this);
	register VObject *vop;

	while (vop= next())
		vop->CalcExtent();
}

OStream& CompositeVObject::PrintOn(OStream &s)
{
	VObject::PrintOn(s);
	return s << list SP;
}

IStream& CompositeVObject::ReadFrom(IStream &s)
{
	Object *op;
	VObject::ReadFrom(s);
	list= 0;
	islist= FALSE;
	s >> op;
	if (op) {
		if (op->IsKindOf(OrdCollection))
			islist= TRUE;
		list= (OrdCollection*) op;
	}
	VObjectIter next(this);
	VObject *vop;
	while (vop= next())
		vop->SetContainer(this);
	return s;
}

